package com.jxl.advice;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 日志记录
 * 使用注解：实现AOP
 * @author 江雪林
 * @create 2021-03-04
 */
@Aspect
@Component
public class ServiceAdvice {
    private static final Logger log = Logger.getLogger(ServiceAdvice.class);

    /**
     * 以某个注解为切入点 @Pontcut("@annotation(Role)")，使用环绕通知实现权限管理
     *
     * 设置切入点
     * 此时pointcut()为切入点的id
     */
    @Pointcut("execution(* com.jxl.service.*.*(..))")
    public void pointcut(){}

    /**
     * 前置增强方法：前置通知
     * @param jp 连接点
     */
    @Before("pointcut()")
    public void before(JoinPoint jp){
        log.info("-> 调用 "+jp.getTarget()+" 的 "+
                jp.getSignature().getName()+" 方法。\n方法入参："+
                Arrays.toString(jp.getArgs())+" <-");
    }

    /**
     * 增强围绕方法：环绕通知
     *  通过环绕通知方法声明 ProceedingJoinPoint 类型的参数可以获取连接点 joinpoint 的信息，
     *  ProceedingJoinPoint 是 JoinPoint 的子接口，其不但封装目标方法及其入参数组，还封装了
     *  被代理的目标对象，通过 proceed() 方法可以调用真正的目标方法，从而达到对连接点的完全控制；
     * @param pjp 程序连接点
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp){
        log.info("-> 开始执行方法："+pjp.getTarget()+" 的 "+pjp.getSignature().getName()+" 方法。<-");
        long strar = System.currentTimeMillis();
        Object obj = null;
        try {
            //程序执行
            obj = pjp.proceed();
        } catch (Throwable throwable) {
            //throwable.printStackTrace();
            log.info("方法执行中出现异常：-> 调用 "+pjp.getTarget()+" 的 "+
                    pjp.getSignature().getName()+" 方法，发生异常，异常信息：\n"+
                    throwable.getMessage()+" <-");
        }finally {
            log.info("方法执行结束，执行时间："+(System.currentTimeMillis()-strar)+" 毫秒 <-");
        }
        return obj;
    }

    /**
     * 异常通知
     * @param e 异常对象
     */
    @AfterThrowing(pointcut = "pointcut()",throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e){
        log.info("异常通知：-> 调用 "+jp.getTarget()+" 的 "+
                jp.getSignature().getName()+" 方法，发生异常，异常信息：\n"+
                e.getMessage()+" <-");
    }

    /**
     * 最终通知
     * @param jp
     */
    @After("pointcut()")
    public void after(JoinPoint jp){
        log.info("-> 调用 "+jp.getTarget()+" 的 "+
                jp.getSignature().getName()+" 方法结束<-");
    }

    /**
     * 后置增强方法：后置通知
     * @param jp 连接点
     * @param result 返回值
     */
    @AfterReturning(pointcut = "pointcut()",returning = "result")
    public void afterReturning(JoinPoint jp,Object result){
        log.info("-> 调用 "+jp.getTarget()+" 的 "+
                jp.getSignature().getName()+" 方法。方法返回值： \n"+
                result+" <-");
    }
}
